import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.LongAdder;

public class LotterySystem {
    private static final int GROUPS = 5;
    private static final int GROUP_SIZE = 1_000_000;
    private final LongAdder[][] groupPrizeRemain;
    private final LongAdder[] groupDrawRemain;
    private static final int[] PHYSICAL_PRIZE_LIMITS = {100, 200, 300, 1000, 2000, 1000, 5000, 8000, 10000};
    private static final String[] PHYSICAL_PRIZES = {"一等奖", "二等奖", "三等奖", "四等奖", "五等奖", "六等奖", "七等奖", "八等奖", "九等奖"};
    private static final double POINT_PRIZE_RATE = 0.9;
    private static final String[] POINT_PRIZES = {"100积分", "20积分", "5积分"};
    private static final int[] POINT_PRIZE_WEIGHTS = {1, 3, 6}; // 1:3:6
    private static final int POINT_PRIZE_WEIGHT_SUM = Arrays.stream(POINT_PRIZE_WEIGHTS).sum();

    public LotterySystem() {
        groupPrizeRemain = new LongAdder[GROUPS][PHYSICAL_PRIZE_LIMITS.length];
        groupDrawRemain = new LongAdder[GROUPS];
        for (int g = 0; g < GROUPS; g++) {
            for (int i = 0; i < PHYSICAL_PRIZE_LIMITS.length; i++) {
                groupPrizeRemain[g][i] = new LongAdder();
                groupPrizeRemain[g][i].add(PHYSICAL_PRIZE_LIMITS[i] / GROUPS);
            }
            groupDrawRemain[g] = new LongAdder();
            groupDrawRemain[g].add(GROUP_SIZE);
        }
    }

    public String draw(User user, int globalDrawNum) {
        int group = Math.min(globalDrawNum / GROUP_SIZE, GROUPS - 1);
        if (groupDrawRemain[group].sum() <= 0) {
            return allocatePointPrizeOrDefault();
        }
        groupDrawRemain[group].decrement();
        if (groupDrawRemain[group].sum() < 0) {
            return allocatePointPrizeOrDefault();
        }
        int remainDraws = (int) groupDrawRemain[group].sum();
        for (int i = 0; i < PHYSICAL_PRIZES.length; i++) {
            if (tryAllocatePhysicalPrize(group, i, remainDraws)) {
                return PHYSICAL_PRIZES[i];
            }
        }
        return allocatePointPrizeOrDefault();
    }

    private boolean tryAllocatePhysicalPrize(int group, int prizeIndex, int remainDraws) {
        if (groupPrizeRemain[group][prizeIndex].sum() > 0 && remainDraws > 0) {
            int totalDraws = GROUP_SIZE - remainDraws; // 当前扫码次数

            // 限制一二等奖的中奖条件
            if (prizeIndex <= 1 && totalDraws < 50000) { // 一等奖或二等奖
                return false;
            }

            // 计算基础中奖概率
            double baseRate = (double) groupPrizeRemain[group][prizeIndex].sum() / remainDraws;

            if (ThreadLocalRandom.current().nextDouble() < baseRate) {
                groupPrizeRemain[group][prizeIndex].decrement();
                return true;
            }
        }
        return false;
    }
    private String allocatePointPrizeOrDefault() {
        if (ThreadLocalRandom.current().nextDouble() < POINT_PRIZE_RATE) {
            int rand = ThreadLocalRandom.current().nextInt(POINT_PRIZE_WEIGHT_SUM);
            int acc = 0;
            for (int i = 0; i < POINT_PRIZES.length; i++) {
                acc += POINT_PRIZE_WEIGHTS[i];
                if (rand < acc) {
                    return POINT_PRIZES[i];
                }
            }
        }
        return "谢谢参与";
    }
}